Contents
  1. 1. 分析:

参考:《改善java程序的151个建议》
http://blog.csdn.net/chenssy/article/details/44102915

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Lian4 {

public static void main(String[] args) {
List<String> c = new ArrayList<String>();
c.add("A");
c.add("B");
//构造一个包含c列表的字符串列表
List<String> c1 = new ArrayList<String>(c);

List<String> c2 = c.subList(0, c.size());

c2.add("C");
System.out.println("c == c1 ? " + c.equals(c1));
System.out.println("c == c2 ? " + c.equals(c2));

}
}

输出:
false
true

分析:

  • 先来看看源码:
1.    public List<E> subList(int fromIndex, int toIndex) {  
2.            subListRangeCheck(fromIndex, toIndex, size);  
3.            return new SubList(this, 0, fromIndex, toIndex);  //注意这个this,是原列表
4.        }  
5.    /** 
6.         * 继承AbstractList类,实现RandomAccess接口 
7.         */  
8.        private class SubList extends AbstractList<E> implements RandomAccess {  
9.            private final AbstractList<E> parent;    //列表  
10.            private final int parentOffset;     
11.            private final int offset;  
12.            int size;  
13.      
14.            //构造函数  
15.            SubList(AbstractList<E> parent,  
16.                    int offset, int fromIndex, int toIndex) {  
17.                this.parent = parent;  
18.                this.parentOffset = fromIndex;  
19.                this.offset = offset + fromIndex;  
20.                this.size = toIndex - fromIndex;  
21.                this.modCount = ArrayList.this.modCount;  
22.            }  
23.      
24.            //set方法  
25.            public E set(int index, E e) {  
26.                rangeCheck(index);  
27.                checkForComodification();  
28.                E oldValue = ArrayList.this.elementData(offset + index);  
29.                ArrayList.this.elementData[offset + index] = e;  
30.                return oldValue;  
31.            }  
32.      
33.            //get方法  
34.            public E get(int index) {  
35.                rangeCheck(index);  
36.                checkForComodification();  
37.                return ArrayList.this.elementData(offset + index);  
38.            }  
39.      
40.            //add方法  
41.            public void add(int index, E e) {  
42.                rangeCheckForAdd(index);  
43.                checkForComodification();  
44.                parent.add(parentOffset + index, e);  
45.                this.modCount = parent.modCount;  
46.                this.size++;  
47.            }  
48.      
49.            //remove方法  
50.            public E remove(int index) {  
51.                rangeCheck(index);  
52.                checkForComodification();  
53.                E result = parent.remove(parentOffset + index);  
54.                this.modCount = parent.modCount;  
55.                this.size--;  
56.                return result;  
57.            }  
58.        }

  该SubLsit是ArrayList的内部类,它与ArrayList一样,都是继承AbstractList和实现RandomAccess接口。同时也提供了get、set、add、remove等list常用的方法。但是它的构造函数有点特殊,在该构造函数中有两个地方需要注意:

  • 1、this.parent = parent;而parent就是在前面传递过来的list,也就是说this.parent就是原始list的引用。
  • 2、this.offset = offset + fromIndex;this.parentOffset = fromIndex;。同时在构造函数中它甚至将modCount(fail-fast机制)传递过来了。

    get、set、add、remove等都是在原列表上面做操作,它并没有像subString一样生成一个新的对象(subString返回的是新对象,因为String类时final的嘛。)。所以subList返回的只是原列表的一个视图,它所有的操作最终都会作用在原列表上。

    再来看看c与c1为什么不相等,因为通过ArrayList构造函数创建的c1实际上是新列表,他是通过数组的copyOf动作生成的,所以生成的列表c1与原列表c之间没有关系(虽然是浅拷贝,但元素类型是String,也就相当于深拷贝了),c修改了与c1无关。

Contents
  1. 1. 分析: